#include "modbusProtocolTable.h"
#include "db.h"
#include "logger.h"
#include "version.h"
#include <string.h>
#include <stdlib.h>

/**
 * 
 */
#define MODBUS_POINT_TABLE_NAME "t_modbus_point"
#define SQL_MODBUS_POINT_TABLE_CREATE "CREATE TABLE IF NOT EXISTS " MODBUS_POINT_TABLE_NAME " (id INT PRIMARY KEY NOT NULL,  \
protocolID INT NOT NULL, modelID INT NOT NULL, modelPointID INT NOT NULL, name TEXT NOT NULL, \
dataType INT NOT NULL , regAddr INT NOT NULL, regNum INT NOT NULL, funcCode INT NOT NULL, pos INT NOT NULL , \
bits INT NOT NULL, scale REAL NOT NULL, decimal INT NOT NULL,endian TEXT NOT NULL, formula TEXT NOT NULL)"
#define SQL_MODBUS_POINT_TABLE_INSERT(...) "INSERT INTO " MODBUS_POINT_TABLE_NAME "(id, protocolID, modelID, modelPointID, name, dataType, regAddr, regNum, funcCode, pos, bits, scale, decimal, endian, formula) VALUES (" #__VA_ARGS__ ")"
#define SQL_MODBUS_POINT_TABLE_REPLACE(...) "REPLACE INTO " MODBUS_POINT_TABLE_NAME "(id, protocolID, modelID, modelPointID, name, dataType, regAddr, regNum, funcCode, pos, bits, scale, decimal, endian, formula) VALUES (" #__VA_ARGS__ ")"
#define SQL_MODBUS_POINT_TABLE_DELETE(id) "DELETE FROM " MODBUS_POINT_TABLE_NAME " WHERE id = " #id
#define SQL_MODBUS_POINT_TABLE_SELECT(id) "SELECT * FROM " MODBUS_POINT_TABLE_NAME " WHERE id = " #id

/**
 * 
 */
#define MODBUS_COMMAND_TABLE_NAME "t_modbus_command"
#define SQL_MODBUS_COMMAND_TABLE_CREATE "CREATE TABLE IF NOT EXISTS " MODBUS_COMMAND_TABLE_NAME " (id INT PRIMARY KEY NOT NULL,  \
protocolID INT NOT NULL, pointID INT NOT NULL, modelID INT NOT NULL, modelcTRLPointID INT NOT NULL, name TEXT NOT NULL, \
dataType INT NOT NULL , regAddr INT NOT NULL, regNum INT NOT NULL, funcCode INT NOT NULL, pos INT NOT NULL , \
bits INT NOT NULL, scale REAL NOT NULL, decimal INT NOT NULL,endian TEXT NOT NULL, formula TEXT NOT NULL, value TEXT NOT NULL)"
#define SQL_MODBUS_COMMAND_TABLE_INSERT(...) "INSERT INTO " MODBUS_COMMAND_TABLE_NAME "(id, protocolID, pointID, modelID, modelCtrlPointID, name, dataType, regAddr, regNum, funcCode, pos, bits, scale, decimal, endian, formula, value) VALUES (" #__VA_ARGS__ ")"
#define SQL_MODBUS_COMMAND_TABLE_REPLACE(...) "REPLACE INTO " MODBUS_COMMAND_TABLE_NAME "(id, protocolID, pointID, modelID, modelCtrlPointID, name, dataType, regAddr, regNum, funcCode, pos, bits, scale, decimal, endian, formula, value) VALUES (" #__VA_ARGS__ ")"
#define SQL_MODBUS_COMMAND_TABLE_DELETE(id) "DELETE FROM " MODBUS_COMMAND_TABLE_NAME " WHERE id = " #id
#define SQL_MODBUS_COMMAND_TABLE_SELECT(id) "SELECT * FROM " MODBUS_COMMAND_TABLE_NAME " WHERE id = " #id
/**
 * 
 */
#define MODBUS_REQUEST_TABLE_NAME "t_modbus_request"
#define SQL_MODBUS_REQUEST_TABLE_CREATE "CREATE TABLE IF NOT EXISTS " MODBUS_REQUEST_TABLE_NAME " (id INT PRIMARY KEY NOT NULL,  \
protocolID INT NOT NULL, name TEXT NOT NULL, dataType INT NOT NULL , regAddr INT NOT NULL, regNum INT NOT NULL, funcCode)"
#define SQL_MODBUS_REQUEST_TABLE_INSERT(...) "INSERT INTO " MODBUS_REQUEST_TABLE_NAME "(id, protocolID, modelID, modelPointID, name, dataType, regAddr, regNum, funcCode, pos, bits, scale, decimal, endian, formula) VALUES (" #__VA_ARGS__ ")"
#define SQL_MODBUS_REQUEST_TABLE_REPLACE(...) "REPLACE INTO " MODBUS_REQUEST_TABLE_NAME "(id, protocolID, modelID, modelPointID, name, dataType, regAddr, regNum, funcCode, pos, bits, scale, decimal, endian, formula) VALUES (" #__VA_ARGS__ ")"
#define SQL_MODBUS_REQUEST_TABLE_DELETE(id) "DELETE FROM " MODBUS_REQUEST_TABLE_NAME " WHERE id = " #id
#define SQL_MODBUS_REQUEST_TABLE_SELECT(id) "SELECT * FROM " MODBUS_REQUEST_TABLE_NAME " WHERE id = " #id


/*===============================================================*/
/* modbus 点表 */
int createModbusPointTable(){
    return db_create_table(SQL_MODBUS_POINT_TABLE_CREATE);
}

int insertModbusPoint(T_PROTOCOL_MODBUS_POINT* point){
    if(NULL == point){
        log_file_e(APPNAME, "insert modbus point is NULL");
        return -1;
    }
    if((NULL == point->name) || (1 > strlen(point->name))){
        log_file_e(APPNAME, "insert modbus point name is NULL or empty");
        return -1;
    }
    
    return db_insert(SQL_MODBUS_POINT_TABLE_INSERT(point->id, point->protocolID, point->modelID, point->modelPointID,
        point->name, point->dataType, point->regAddr, point->regNum, point->funcCode, point->pos, point->bits, 
        point->scale, point->decimal, point->endian, point->formula));
}
/**
 * 
 */
int replaceModbusPoint(T_PROTOCOL_MODBUS_POINT* point){
    if(NULL == point){
        log_file_e(APPNAME, "replace point is NULL");
        return -1;
    }
    if((NULL == point->name) || (1 > strlen(point->name))){
        log_file_e(APPNAME, "replace point name is NULL or empty");
        return -1;
    }
    return db_insert(SQL_MODBUS_POINT_TABLE_REPLACE(point->id, point->protocolID, point->modelID, point->modelPointID,
        point->name, point->dataType, point->regAddr, point->regNum, point->funcCode, point->pos, point->bits, 
        point->scale, point->decimal, point->endian, point->formula));
}

int deleteModbusPoint(T_PROTOCOL_MODBUS_POINT* point){
    if(NULL == point){
        log_file_e(APPNAME, "delete modbus point is NULL");
        return -1;
    }
    return db_delete(SQL_MODBUS_POINT_TABLE_DELETE(point->id));
}
/**
 *  
 */
static int modbusPointCallback(void *data, int argc, char **argv, char **azColName){
    int i = 0;
    if(NULL == data){
        log_file_e(APPNAME, "modbusPointCallback data is NULL");
        return -1;
    }
    T_PROTOCOL_MODBUS_POINT_LIST* pointList = (T_PROTOCOL_MODBUS_POINT_LIST*)data;
    if((0 == pointList->count) || (NULL == pointList->head)){
        pointList->head = pointList->tail = (T_PROTOCOL_MODBUS_POINT*)malloc(sizeof(T_PROTOCOL_MODBUS_POINT));
        pointList->head->next = NULL;
        pointList->head->prev = NULL;
    } else {
        pointList->tail->next = (T_PROTOCOL_MODBUS_POINT*)malloc(sizeof(T_PROTOCOL_MODBUS_POINT));
        pointList->tail->next->prev = pointList->tail;
        pointList->tail = pointList->tail->next;
    }
    pointList->count++;
    for(i = 0; i < argc; i++){
        if(0 == strcmp(azColName[i], "id")){
            pointList->tail->id = atoll(argv[i]);
        } else if(0 == strcmp(azColName[i], "protocolID")){
            pointList->tail->protocolID = atoll(argv[i]);
        } else if(0 == strcmp(azColName[i], "modelID")){
            pointList->tail->modelID = atoll(argv[i]);
        } else if(0 == strcmp(azColName[i], "modelPointID")){
            pointList->tail->modelPointID = atoll(argv[i]);
        } else if(0 == strcmp(azColName[i], "name")){
            if(NULL == argv[i]){
                pointList->tail->name[0] = '\0';
            } else {
                strcpy(pointList->tail->name, argv[i]);
            }
        } else if(0 == strcmp(azColName[i], "dataType")){
            pointList->tail->dataType = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "regAddr")){
            pointList->tail->regAddr = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "regNum")){
            pointList->tail->regNum = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "funcCode")){
            pointList->tail->funcCode = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "pos")){
            pointList->tail->pos = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "bits")){
            pointList->tail->bits = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "scale")){
            pointList->tail->scale = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "formula")){
            if(NULL == argv[i]){
                pointList->tail->formula[0] = '\0';
            } else {
                strcpy(pointList->tail->formula, argv[i]);
            }
        } else if(0 == strcmp(azColName[i], "decimal")){
            pointList->tail->decimal = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "endian")){
            if(NULL == argv[i]){
                pointList->tail->endian[0] = '\0';
            } else {
                strcpy(pointList->tail->endian, argv[i]);
            }
        }
        log_i("%s = %s", azColName[i], argv[i] ? argv[i] : "NULL");
    }
    return pointList->count;
}

int selectModbusPoint(const char* sql, T_PROTOCOL_MODBUS_POINT_LIST* pointList){
    if((NULL == sql) || (1 > strlen(sql)) || (NULL == pointList)){
        log_file_e(APPNAME, "select modbus point sql is NULL");
        return -1;
    }
    return db_select(sql, modbusPointCallback, pointList);

}
/*===============================================================*/
/* modbus 指令表 */
int createModbusCtrlPointTable(){
    return db_create_table(SQL_MODBUS_COMMAND_TABLE_CREATE);
}

int insertModbusCtrlPoint(T_PROTOCOL_MODBUS_CTRL_POINT* ctrlPoint){
    if(NULL == ctrlPoint){
        log_file_e(APPNAME, "insert modbus ctrl point is NULL");
        return -1;
    }
    if((NULL == ctrlPoint->name) || (1 > strlen(ctrlPoint->name))){
        log_file_e(APPNAME, "insert modbus ctrl point name is NULL or empty");
        return -1;
    }
    
    return db_insert(SQL_MODBUS_COMMAND_TABLE_INSERT(ctrlPoint->id, ctrlPoint->protocolID, ctrlPoint->pointID, ctrlPoint->modelID, ctrlPoint->modelCtrlctrlPointID,
        ctrlPoint->name, ctrlPoint->dataType, ctrlPoint->regAddr, ctrlPoint->regNum, ctrlPoint->funcCode, ctrlPoint->pos, ctrlPoint->bits, ctrlPoint->scale, ctrlPoint->decimal,
        ctrlPoint->endian, ctrlPoint->formula, ctrlPoint->value));
}
/**
 * 
 */
int replaceModbusCtrlPoint(T_PROTOCOL_MODBUS_CTRL_POINT* ctrlPoint){
    if(NULL == ctrlPoint){
        log_file_e(APPNAME, "replace point is NULL");
        return -1;
    }
    if((NULL == ctrlPoint->name) || (1 > strlen(ctrlPoint->name))){
        log_file_e(APPNAME, "replace point name is NULL or empty");
        return -1;
    }
    return db_insert(SQL_MODBUS_COMMAND_TABLE_REPLACE(ctrlPoint->id, ctrlPoint->protocolID, ctrlPoint->pointID, ctrlPoint->modelID, ctrlPoint->modelCtrlPointID,
        ctrlPoint->name, ctrlPoint->dataType, ctrlPoint->regAddr, ctrlPoint->regNum, ctrlPoint->funcCode, ctrlPoint->pos, ctrlPoint->bits, ctrlPoint->scale, ctrlPoint->decimal,
        ctrlPoint->endian, ctrlPoint->formula, ctrlPoint->value));
}

int deleteModbusCtrlPoint(T_PROTOCOL_MODBUS_CTRL_POINT* ctrlPoint){
    if(NULL == ctrlPoint){
        log_file_e(APPNAME, "delete modbus point is NULL");
        return -1;
    }
    return db_delete(SQL_MODBUS_COMMAND_TABLE_DELETE(ctrlPoint->id));
}

static int modbusCtrlPointCallback(void *data, int argc, char **argv, char **azColName){
    int i = 0;
    if(NULL == data){
        log_file_e(APPNAME, "modbus ctrl point callback data is NULL");
        return -1;
    }
    T_PROTOCOL_MODBUS_CTRL_POINT_LIST* cmdList = (T_PROTOCOL_MODBUS_CTRL_POINT_LIST*)data;
    if((0 == cmdList->count) || (NULL == cmdList->head)){
        cmdList->head = cmdList->tail = (T_PROTOCOL_MODBUS_CTRL_POINT*)malloc(sizeof(T_PROTOCOL_MODBUS_CTRL_POINT));
        cmdList->head->next = NULL;
        cmdList->head->prev = NULL;
    } else {
        cmdList->tail->next = (T_PROTOCOL_MODBUS_CTRL_POINT*)malloc(sizeof(T_PROTOCOL_MODBUS_CTRL_POINT));
        cmdList->tail->next->prev = cmdList->tail;
        cmdList->tail = cmdList->tail->next;
    }
    cmdList->count++;
    for(i = 0; i < argc; i++){
        if(0 == strcmp(azColName[i], "id")){
            cmdList->tail->id = atoll(argv[i]);
        } else if(0 == strcmp(azColName[i], "protocolID")){
            cmdList->tail->protocolID = atoll(argv[i]);
        } else if(0 == strcmp(azColName[i], "pointID")){
            cmdList->tail->pointID = atoll(argv[i]);
        } else if(0 == strcmp(azColName[i], "modelID")){
            cmdList->tail->modelID = atoll(argv[i]);
        } else if(0 == strcmp(azColName[i], "modelCtrlPointID")){
            cmdList->tail->modelCtrlPointID = atoll(argv[i]);
        } else if(0 == strcmp(azColName[i], "name")){
            if(NULL == argv[i]){
                cmdList->tail->name[0] = '\0';
            } else {
                strcpy(cmdList->tail->name, argv[i]);
            }
        } else if(0 == strcmp(azColName[i], "dataType")){
            cmdList->tail->dataType = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "regAddr")){
            cmdList->tail->regAddr = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "regNum")){
            cmdList->tail->regNum = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "funcCode")){
            cmdList->tail->funcCode = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "pos")){
            cmdList->tail->pos = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "bits")){
            cmdList->tail->bits = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "scale")){
            cmdList->tail->scale = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "formula")){
            if(NULL == argv[i]){
                cmdList->tail->formula[0] = '\0';
            } else {
                strcpy(cmdList->tail->formula, argv[i]);
            }
        } else if(0 == strcmp(azColName[i], "decimal")){
            cmdList->tail->decimal = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "endian")){
            if(NULL == argv[i]){
                cmdList->tail->endian[0] = '\0';
            } else {
                strcpy(cmdList->tail->endian, argv[i]);
            }
        } else if(0 == strcmp(azColName[i], "value")){
            if(NULL == argv[i]){
                cmdList->tail->value[0] = '\0';
            } else {
                strcpy(cmdList->tail->value, argv[i]);
            }
        }
        log_i("%s = %s", azColName[i], argv[i] ? argv[i] : "NULL");
    }
    return cmdList->count;
}
int selectModbusCtrlPoint(const char* sql, T_PROTOCOL_MODBUS_CTRL_POINT_LIST* cmdList){
    if((NULL == sql) || (1 > strlen(sql)) || (NULL == cmdList)){
        log_file_e(APPNAME, "select modbus command sql is NULL");
        return -1;
    }
    return db_select(sql, modbusCtrlPointCallback, cmdList);

}
/*===============================================================*/
/* modbus 请求表 */
int createModbusRequestTable(){
    return db_create_table(SQL_MODBUS_REQUEST_TABLE_CREATE);
}

int insertModbusRequest(T_PROTOCOL_MODBUS_REQUEST* request){
    if(NULL == request){
        log_file_e(APPNAME, "insert modbus request is NULL");
        return -1;
    }
    if((NULL == request->name) || (1 > strlen(request->name))){
        log_file_e(APPNAME, "insert modbus request name is NULL or empty");
        return -1;
    }
    
    return db_insert(SQL_MODBUS_POINT_TABLE_INSERT(request->id, request->protocolID, request->name, 
        request->dataType, request->regAddr, request->regNum, request->funcCode));
}
/**
 * 
 */
int replaceModbusRequest(T_PROTOCOL_MODBUS_REQUEST* request){
    if(NULL == request){
        log_file_e(APPNAME, "replace modbus request is NULL");
        return -1;
    }
    return db_insert(SQL_MODBUS_POINT_TABLE_REPLACE(request->id, request->protocolID, request->name, 
        request->dataType, request->regAddr, request->regNum, request->funcCode));
}

int deleteModbusRequest(T_PROTOCOL_MODBUS_REQUEST* request){
    if(NULL == request){
        log_file_e(APPNAME, "delete modbus request is NULL");
        return -1;
    }
    return db_delete(SQL_MODBUS_POINT_TABLE_DELETE(request->id));
}

static int modbusRequestCallback(void *data, int argc, char **argv, char **azColName){
    int i = 0;
    if(NULL == data){
        log_file_e(APPNAME, "modbus request callback data is NULL");
        return -1;
    }
    T_PROTOCOL_MODBUS_REQUEST_LIST* cmdList = (T_PROTOCOL_MODBUS_REQUEST_LIST*)data;
    if((0 == cmdList->count) || (NULL == cmdList->head)){
        cmdList->head = cmdList->tail = (T_PROTOCOL_MODBUS_REQUEST*)malloc(sizeof(T_PROTOCOL_MODBUS_REQUEST));
        cmdList->head->next = NULL;
        cmdList->head->prev = NULL;
    } else {
        cmdList->tail->next = (T_PROTOCOL_MODBUS_REQUEST*)malloc(sizeof(T_PROTOCOL_MODBUS_REQUEST));
        cmdList->tail->next->prev = cmdList->tail;
        cmdList->tail = cmdList->tail->next;
    }
    cmdList->count++;
    for(i = 0; i < argc; i++){
        if(0 == strcmp(azColName[i], "id")){
            cmdList->tail->id = atoll(argv[i]);
        } else if(0 == strcmp(azColName[i], "protocolID")){
            cmdList->tail->protocolID = atoll(argv[i]);
        } else if(0 == strcmp(azColName[i], "name")){
            if(NULL == argv[i]){
                cmdList->tail->name[0] = '\0';
            } else {
                strcpy(cmdList->tail->name, argv[i]);
            }
        } else if(0 == strcmp(azColName[i], "dataType")){
            cmdList->tail->dataType = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "regAddr")){
            cmdList->tail->regAddr = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "regNum")){
            cmdList->tail->regNum = atoi(argv[i]);
        } else if(0 == strcmp(azColName[i], "funcCode")){
            cmdList->tail->funcCode = atoi(argv[i]);
        }
        log_i("%s = %s", azColName[i], argv[i] ? argv[i] : "NULL");
    }
    return cmdList->count;
}
int selectModbusRequest(const char* sql, T_PROTOCOL_MODBUS_REQUEST_LIST* reqList){
    if((NULL == sql) || (1 > strlen(sql)) || (NULL == reqList)){
        log_file_e(APPNAME, "select modbus command sql is NULL");
        return -1;
    }
    return db_select(sql, modbusRequestCallback, reqList);

}
//
void dbModbusInit(){
    createModbusPointTable();
    createModbusCtrlPointTable();
    createModbusRequestTable();
}
